using System;
using System.Globalization;

namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
{
	public class BComparisons
	{
		public static int Main()
		{
			TestFloatOp("==", (float a, float b) => a == b);
			TestFloatOp("!=", (float a, float b) => a != b);
			TestFloatOp("<", (float a, float b) => a < b);
			TestFloatOp(">", (float a, float b) => a > b);
			TestFloatOp("<=", (float a, float b) => a <= b);
			TestFloatOp(">=", (float a, float b) => a >= b);
			TestFloatOp("!<", (float a, float b) => !(a < b));
			TestFloatOp("!>", (float a, float b) => !(a > b));
			TestFloatOp("!<=", (float a, float b) => !(a <= b));
			TestFloatOp("!>=", (float a, float b) => !(a >= b));
			TestUInt(0u);
			TestUInt(uint.MaxValue);
			TestUShort(0);
			TestUShort(ushort.MaxValue);
			Console.WriteLine(IsNotNull(new BOverloadedOperators()));
			Console.WriteLine(IsNull(new BOverloadedOperators()));
			Console.WriteLine(NullIs(new BOverloadedOperators()));
			Console.WriteLine(NullIsNot(new BOverloadedOperators()));
			return 0;
		}

		private static void TestFloatOp(string name, Func<float, float, bool> f)
		{
			float[] vals = new float[5] {
				-1f,
				0f,
				3f,
				float.PositiveInfinity,
				float.NaN
			};
			for (int i = 0; i < vals.Length; i++) {
				for (int j = 0; j < vals.Length; j++) {
					Console.WriteLine("Float: {0} {1} {2:r} = {3}", vals[i].ToString("r", CultureInfo.InvariantCulture), name, vals[j].ToString("r", CultureInfo.InvariantCulture), f(vals[i], vals[j]));
				}
			}
		}

		private static T Id<T>(T arg)
		{
			return arg;
		}

		private static void TestUShort(ushort i)
		{
			Console.WriteLine("ushort: {0} == ushort.MaxValue = {1}", i, i == ushort.MaxValue);
			Console.WriteLine("ushort: {0} == -1 = {1}", i, i == -1);
			Console.WriteLine("ushort: {0} == Id<short>(-1) = {1}", i, i == Id((short)(-1)));
			Console.WriteLine("ushort: {0} == 0x1ffff = {1}", i, i == 131071);
		}

		private static void TestUInt(uint i)
		{
			Console.WriteLine("uint: {0} == uint.MaxValue = {1}", i, i == uint.MaxValue);
			Console.WriteLine("uint: {0} == Id(uint.MaxValue) = {1}", i, i == Id(uint.MaxValue));
			Console.WriteLine("uint: {0} == -1 = {1}", i, i == -1);
			Console.WriteLine("uint: {0} == Id(-1) = {1}", i, i == Id(-1));
		}

		private static bool IsNull(BOverloadedOperators oo)
		{
			return (object)oo == null;
		}

		private static bool IsNotNull(BOverloadedOperators oo)
		{
			return (object)oo != null;
		}

		private static bool NullIs(BOverloadedOperators oo)
		{
			return (object)null == (object)oo;
		}

		private static bool NullIsNot(BOverloadedOperators oo)
		{
			return (object)null != (object)oo;
		}
	}
	internal class BOverloadedOperators
	{
		public static bool operator ==(BOverloadedOperators oo, object b)
		{
			throw new NotSupportedException("Not supported to call the user-defined operator");
		}

		public static bool operator !=(BOverloadedOperators oo, object b)
		{
			throw new NotSupportedException("Not supported to call the user-defined operator");
		}

		public static bool operator ==(object oo, BOverloadedOperators b)
		{
			throw new NotSupportedException("Not supported to call the user-defined operator");
		}

		public static bool operator !=(object oo, BOverloadedOperators b)
		{
			throw new NotSupportedException("Not supported to call the user-defined operator");
		}
	}
}
